home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqdisplay / texture.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-12  |  12.8 KB  |  453 lines

  1. #define    LIBQDISPLAY_CORE
  2. #include "../include/libqdisplay.h"
  3.  
  4. //#define    scalw(x, y)    (x * (1 << y))
  5.  
  6. unsigned char *waterTransparency;    // 50
  7. unsigned char *slimeTransparency;    // 75
  8. unsigned char *lavaTransparency;    // 90
  9. unsigned char *preTransparency;        // do not calculate in the loop
  10.  
  11. unsigned char *texture;
  12. int textureRow;
  13. int textureMask1, textureMask2;
  14. short int textureShift1, textureShift2;
  15. short int textureMip;
  16. short int textureType;
  17. static int skyMovementX1 = 0, skyMovementY1 = 0;
  18. static int skyMovementX2 = 0, skyMovementY2 = 0;
  19. static float tmap[9];
  20. #ifndef    FAST_WARP
  21. int swim_u[256], swim_v[256], swim_phase;
  22. #else
  23. int *swim_u, *swim_v, swim_phase;
  24. int swim_u0[WARP_X >> MIPMAP_0], swim_v0[WARP_X >> MIPMAP_0];
  25. int swim_u1[WARP_X >> MIPMAP_1], swim_v1[WARP_X >> MIPMAP_1];
  26. int swim_u2[WARP_X >> MIPMAP_2], swim_v2[WARP_X >> MIPMAP_2];
  27. int swim_u3[WARP_X >> MIPMAP_3], swim_v3[WARP_X >> MIPMAP_3];
  28. int *swim_um[MIPMAP_MAX] = {swim_u0, swim_u1, swim_u2, swim_u3};
  29. int *swim_vm[MIPMAP_MAX] = {swim_v0, swim_v1, swim_v2, swim_v3};
  30. #endif
  31.  
  32. /*
  33.  * NOTE: subdivision of 16 is a really hard thig, it works most, but you can see sometimes curved textures
  34.  *       if you have some processorpower use 8 instead!
  35.  */
  36. #define SUBDIV_SHIFT    4
  37. #define SUBDIV        (1 << SUBDIV_SHIFT)
  38. #define    SUBDIV_MASK    (SUBDIV - 1)
  39.  
  40. /*
  41.  * Warping water.
  42.  * 
  43.  * tx = H_AMPL * sin(2.0 * PI * (y / V_PERIOD + t / T_PERIOD));
  44.  * ty = V_AMPL * cos(2.0 * PI * (x / H_PERIOD + t / T_PERIOD));
  45.  * 
  46.  * - amplitudes: H_AMPL and V_AMPL,
  47.  * - repetition periods: H_PERIOD and V_PERIOD,
  48.  * - time repetition period: T_PERIOD.
  49.  * 
  50.  * - Ex: a period(spacing) of 128 and an amplitude of 8:
  51.  * tx = 8.0 * sin(2.0 * PI * y / 128.0);
  52.  * ty = 8.0 * cos(2.0 * PI * x / 128.0);
  53.  */
  54. void update_water(void)
  55. {
  56.   short int i;
  57.  
  58.   swim_phase++;
  59. #ifndef    FAST_WARP
  60.   for (i = 0; i < 256; ++i) {
  61.     //swim_u[i] = FLOAT_FIX(sin(((i >> 6) + (swim_phase >> 6)) * M_PI * 2.0) * 8.0);
  62.     //swim_v[i] = FLOAT_FIX(cos(((i >> 6) + (swim_phase >> 6)) * M_PI * 2.0) * 8.0);
  63.     //swim_u[i] = scalw(sin(((i + swim_phase) * .09817477)), 19);
  64.     //swim_v[i] = scalw(cos(((i + swim_phase) * .09817477)), 19);
  65.     double val = (i + swim_phase) * .09817477;
  66.     int val_u = scalw(sin(val), 19);                    // * 524288;
  67.     int val_v = scalw(cos(val), 19);                    // * 524288;
  68.     
  69.     swim_u[i] = val_u;                    // mip0
  70.     swim_v[i] = val_v;
  71.   }
  72. #else
  73.   for (i = 0; i < WARP_X; ++i) {
  74.     double val = (i + swim_phase) * .09817477;
  75.     int val_u = scalw(sin(val), 19);                    // * 524288;
  76.     int val_v = scalw(cos(val), 19);                    // * 524288;
  77.     
  78.     swim_u0[i] = val_u;                    // mip0
  79.     swim_v0[i] = val_v;
  80.     if(!(i & ((1 << MIPMAP_1) - 1))) {
  81.       swim_u1[i >> MIPMAP_1] = val_u >> MIPMAP_1;    // mip1
  82.       swim_v1[i >> MIPMAP_1] = val_v >> MIPMAP_1;
  83.       if(!(i & ((1 << MIPMAP_2) - 1))) {
  84.         swim_u2[i >> MIPMAP_2] = val_u >> MIPMAP_2;    // mip2
  85.         swim_v2[i >> MIPMAP_2] = val_v >> MIPMAP_2;
  86.         if(!(i & ((1 << MIPMAP_3) - 1))) {
  87.           swim_u3[i >> MIPMAP_3] = val_u >> MIPMAP_3;    // mip3
  88.           swim_v3[i >> MIPMAP_3] = val_v >> MIPMAP_3;
  89.         }
  90.       }
  91.     }
  92.   }
  93. #endif
  94.  
  95.   skyMovementX1 += 0x00000100;
  96.   skyMovementY1 += 0x00000001;
  97.   skyMovementX2 += 0x00000200;
  98.   skyMovementY2 += 0x00000002;
  99. }
  100.  
  101. short int compute_mip_level(__memBase, int face)
  102. {
  103.   // dumb algorithm: grab 3d coordinate of some vertex,
  104.   // compute dist from viewer
  105.   double dist;
  106.   int se = bspMem->dfaces[face].firstedge;
  107.   int e = bspMem->dsurfedges[se];
  108.  
  109.   if (e < 0)
  110.     e = -e;
  111.   dist = scalw(dist2_from_viewer(&bspMem->dvertexes[bspMem->dedges[e].v[0]].point), -16);    // / 65536;
  112.   if (dist < 1)
  113.     return 0;
  114.   if (dist < 4)
  115.     return 1;
  116.   if (dist < 16)
  117.     return 2;
  118.   return 3;
  119. }
  120.  
  121. void compute_texture_gradients(__memBase, struct texture *Text, short int mip)
  122. {
  123.   //double tmap_data[9];
  124.   float uu, vv;
  125.   float tmp0, tmp1, tmp2;
  126.   vec3_t P, M, N;
  127.  
  128.   // project vectors onto face's plane, and transform
  129.   transform_vector(M, Text->textGradient.uv0);
  130.   transform_vector(N, Text->textGradient.uv1);
  131.   transform_point_raw(P, Text->textGradient.scaled);
  132.  
  133.   uu = Text->textGradient.u;
  134.   vv = Text->textGradient.v;
  135.  
  136.   // we could just subtract (u,v) every time we compute a new (u,v);
  137.   // instead we fold it into P:
  138.   P[0] += uu * M[0] + vv * N[0];
  139.   P[1] += uu * M[1] + vv * N[1];
  140.   P[2] += uu * M[2] + vv * N[2];
  141.  
  142.   // offset by Center of screen--if this were folded into
  143.   // transform translation we could avoid it
  144.   tmp2 = N[0] * M[2] - N[2] * M[0];
  145.   tmp1 = N[1] * M[2] - N[2] * M[1];
  146.   tmp0 = N[0] * M[1] - N[1] * M[0];
  147.   tmp0 -= tmp1 * xCenter + tmp2 * yCenter;
  148.   tmap[8] = tmp2;
  149.   tmap[7] = tmp1;
  150.   tmap[6] = tmp0;
  151.   
  152.   tmp2 = P[2] * M[0] - P[0] * M[2];
  153.   tmp1 = P[2] * M[1] - P[1] * M[2];
  154.   tmp0 = P[1] * M[0] - P[0] * M[1];
  155.   tmp0 -= tmp1 * xCenter + tmp2 * yCenter;
  156.   tmap[5] = scalw(tmp2, -mip);
  157.   tmap[4] = scalw(tmp1, -mip);
  158.   tmap[3] = scalw(tmp0, -mip);
  159.   
  160.   tmp2 = P[0] * N[2] - P[2] * N[0];
  161.   tmp1 = P[1] * N[2] - P[2] * N[1];
  162.   tmp0 = P[0] * N[1] - P[1] * N[0];
  163.   tmp0 -= tmp1 * xCenter + tmp2 * yCenter;
  164.   tmap[2] = scalw(tmp2, -mip);
  165.   tmap[1] = scalw(tmp1, -mip);
  166.   tmap[0] = scalw(tmp0, -mip);
  167. }
  168.  
  169. // draw an affine (linear) span starting at dest, n pixels long,
  170. // starting at (u,v) in the texture and stepping by (du,dv) each pixel
  171. //static void draw_affine(int n, unsigned char *dest, int u, int v, int du, int dv)
  172. /*
  173.  * if we are in liquid, we can calculate the average pixelcolor
  174.  * of the liquid texture (eg. *lava1) and do a transp with this color
  175.  * so we don't need to change the palette, and the accuracity
  176.  * is better
  177.  *
  178.  * we can make the liquid with a falloff if we use the zbuffer,
  179.  * we have the current z-value, and the z-value at that position
  180.  * we sub them and calculate the transparency-level from that
  181.  * (better use every 10th or like that transparency-level: first,
  182.  *  the transparency is not so accurate, that every percent makes
  183.  *  a change, second, all 100% transparency uses 6,5MB cached
  184.  *  tables, both in memory and on disk (horror!))
  185.  * the falloff is calculated from the brightness of the liquid texture
  186.  * and the type, so brighter texture are more transparent than darker
  187.  *
  188.  * the liquid looks more real if the textures after it also warps
  189.  * so we must determine, which textures lies in liquid, probably
  190.  * we can use the same procedure as the liquid itself, maybe
  191.  * we must project the liquids behaviour to the texture (uff)
  192.  *
  193.  * how to determine if a texture lies in liquid? as I know qbsp
  194.  * splits the plaes at every intersection of two polygons, that
  195.  * means we do not need to split the polygon at the liquid-line
  196.  * the disadvatage of the mark-texture-in-liquid is, that while
  197.  * we are in liquid, the textures outside the liquid doesn't warp
  198.  *
  199.  * probably we can do real wave in liquid, for that we do not change
  200.  * the du or dv, but the z-value (upwards) of the polygon in a
  201.  * reproducable caustics manner, the difficulty is, to calculate this
  202.  * values in the very inner loop (draw_affine), thats slow
  203.  *
  204.  * how to avoid this mipmap shiftig and masking in liquid textures:
  205.  * after building the waterblock convert the scanlines from this:
  206.  *
  207.  * +----+ example: memory-block-size is 64*64
  208.  * |****|       mipmap-size is 32*32
  209.  * |    |       memory is linear
  210.  * |    |
  211.  * |    |
  212.  * +----+
  213.  *
  214.  * interally handled as this:    to this:
  215.  *                
  216.  * +--+                +----+ we need no shiftig, on masking
  217.  * |**|                |**  | and it is faster, 'cause the 
  218.  * |**|                |**  | conversion could be cached and is
  219.  * +--+                |    | out of the span-draw-inner-loop
  220.  *                |    |
  221.  *                 +----+
  222.  *
  223.  * we can even remove all the shifting, if we put the warp-textures
  224.  * in a 256*64 block, so the offset is 0x0000xxyy (0b000000000000000000xxxxxx00yyyyyy)
  225.  * that is a 16k-block per watertexture, not too much
  226.  *
  227.  * probably it could be faster, if we call a hook defined in the TextureCache
  228.  */
  229. static inline unsigned char *draw_affine(int n, unsigned char *dest, int u, int v, int du, int dv)
  230. {
  231.   if (textureType == WALL_TYPE) {
  232.     while (n--) {
  233.       int iu = u >> 16;
  234.       int iv = ((v >> 8) & 0x0000FF00) + textureRow;
  235.  
  236. #ifdef CALCULATE_PIXELDRAW
  237.       pixelDraw++;
  238.       if(*dest)
  239.         pixelOverdraw++;
  240. #endif
  241.       
  242.       *dest++ = texture[multMuls[iv] + iu];
  243.       u += du;
  244.       v += dv;
  245.     }
  246.   }
  247.   else if (textureType == SKY_TYPE) {
  248.     /* TODO: skies */
  249.     while (n--) {
  250.       int iu;
  251.       int iv;
  252.       unsigned char pel, sum;
  253.       
  254. #ifdef CALCULATE_PIXELDRAW
  255.       pixelDraw++;
  256.       if(*dest)
  257.         pixelOverdraw++;
  258. #endif
  259.  
  260.       iu = ((u >> 8) + skyMovementX1) & 0x00007F00;
  261.       iv = ((v >> 16) + skyMovementY1) & 0x0000007F;
  262.       sum = texture[iu + iv + 0x80];
  263.       iu = ((u >> 8) + skyMovementX2) & 0x00007F00;
  264.       iv = ((v >> 16) + skyMovementY2) & 0x0000007F;
  265.       if((pel = texture[iu + iv]))
  266.         sum = pel;
  267.       *dest++ = sum;
  268.  
  269.       u += du;
  270.       v += dv;
  271.     }
  272.   }
  273.   else {
  274.     while (n--) {
  275. #ifndef    FAST_WARP
  276.       int iv = ((v + (swim_v[((u >> textureShift2) & 0xff)] >> textureMip)) >> 16) & textureMask2;
  277.       int iu = ((u + (swim_u[((v >> textureShift2) & 0xff)] >> textureMip)) >> textureShift1) & textureMask1;
  278. #else
  279.       int iv = ((v + swim_v[(u >> 16)]) >> 16) & textureMask2;
  280.       int iu = ((u + swim_u[(v >> 16)]) >> textureShift1) & textureMask1;
  281. #endif
  282.       *dest++ = pretransp(texture[iu + iv], *dest);
  283.       u += du;
  284.       v += dv;
  285.     }
  286.   }
  287.   return dest;
  288. }
  289.  
  290. // given a span (x0,y)..(x1,y), draw a perspective-correct span for it
  291. /*
  292. void draw_span(int y, int sx, int ex)
  293. {
  294.   float u0, v0, w0, u1, v1, w1, z;
  295.   int len, e, last = 0;
  296.   int u, v, du, dv;
  297.   int i, j;
  298.   
  299.   float preu = tmap[0] + y * tmap[2];
  300.   float prev = tmap[3] + y * tmap[5];
  301.   float prew = tmap[6] + y * tmap[8];
  302.  
  303.   // compute (u,v) at left end
  304.   u0 = preu + sx * tmap[1];
  305.   v0 = prev + sx * tmap[4];
  306.   w0 = prew + sx * tmap[7];
  307.   z = (float)((float)(1) / w0);
  308.   u0 = u0 * z;
  309.   v0 = v0 * z;
  310.  
  311.   for (;;) {
  312.     len = ex - sx;
  313.     if (len > SUBDIV)
  314.       len = SUBDIV;
  315.     else
  316.       last = 1;
  317.  
  318.     u = FLOAT_TO_FIX(u0);
  319.     v = FLOAT_TO_FIX(v0);
  320.  
  321.     if (len == 1)
  322.       // shortcut out to avoid divide by 0 below
  323.       du = dv = 0;
  324.     else {
  325.       e = sx + len - last;
  326.       u1 = preu + e * tmap[1];
  327.       v1 = prev + e * tmap[4];
  328.       w1 = prew + e * tmap[7];
  329.       z = (float)((float)(1) / w1);
  330.       u1 = u1 * z;
  331.       v1 = v1 * z;
  332.  
  333.       if (len == SUBDIV) {
  334.         du = (FLOAT_TO_FIX(u1) - u) >> SUBDIV_SHIFT;
  335.         dv = (FLOAT_TO_FIX(v1) - v) >> SUBDIV_SHIFT;
  336.       }
  337.       else {
  338.         du = FLOAT_TO_FIX((u1 - u0) / (len - last));
  339.         dv = FLOAT_TO_FIX((v1 - v0) / (len - last));
  340.       }
  341.       if (du < 0)
  342.         ++du;
  343.       if (dv < 0)
  344.         ++dv;
  345.     }
  346.  
  347.     draw_affine(len, localDim.frameBuffer + multRows[y] + sx, u, v, du, dv);
  348.     if (last)
  349.       break;
  350.  
  351.     sx += len;
  352.     u0 = u1;
  353.     v0 = v1;
  354.   }
  355. }
  356.  
  357. // sx = 16, ex = 32
  358. sx    len    last    /    e
  359. 16    16    1    15    31
  360. // sx = 16, ex = 33
  361. sx    len    last    /    e
  362. 16    17    0    *    32
  363. 33    0    1    -1    32    ...
  364. // sx = 16, ex = 34
  365. sx    len    last    /    e
  366. 16    17    0    *    33
  367. 33    1    1    *    33    ...
  368. //
  369. */
  370. /*
  371.  * the zbuffer is interesting for dynamic model-draw etc.
  372.  * the buffers values (1/z) are all under 0, we can try to
  373.  * store them as 16bit-wide-fraction
  374.  *
  375.  * while(n--) {
  376.  *   *zbuf++ = (w >> 16);
  377.  *   w += dw;
  378.  * }
  379.  *
  380.  */
  381. void draw_span(int y, int sx, int ex)
  382. {
  383.   float w0, w1;
  384.   float v0, v1;
  385.   float u0, u1;
  386. //int w, dw;                        // 1/zbuffer
  387.   int v, dv;
  388.   int u, du;
  389.   int slen, rlen, len, end;
  390.  
  391.   unsigned char *dest = localDim.frameBuffer + multRows[y] + sx;
  392.   float prew = tmap[6] + y * tmap[8];
  393.   float prev = tmap[3] + y * tmap[5];
  394.   float preu = tmap[0] + y * tmap[2];
  395.  
  396.   // compute (u,v) at left end
  397.   w0 = 1 / (prew + sx * tmap[7]);            // 1/zbuffer
  398.   v0 = (prev + sx * tmap[4]) * w0;
  399.   u0 = (preu + sx * tmap[1]) * w0;
  400.  
  401.   len = ex - sx;
  402.   for(slen = len >> SUBDIV_SHIFT; slen > 0 ;slen--) {
  403.   //w = FLOAT_TO_FIX(w0);                // 1/zbuffer
  404.     v = FLOAT_TO_FIX(v0);
  405.     u = FLOAT_TO_FIX(u0);
  406.  
  407.     end = sx + SUBDIV;
  408.     w1 = 1 / (prew + end * tmap[7]);
  409.     v1 = (prev + end * tmap[4]) * w1;
  410.     u1 = (preu + end * tmap[1]) * w1;
  411.  
  412.   //dw = (FLOAT_TO_FIX(v1) - w) >> SUBDIV_SHIFT;    // 1/zbuffer
  413.     dv = (FLOAT_TO_FIX(v1) - v) >> SUBDIV_SHIFT;
  414.     du = (FLOAT_TO_FIX(u1) - u) >> SUBDIV_SHIFT;
  415.  
  416.     dest = draw_affine(SUBDIV, dest, u, v, du, dv);
  417.     sx = end;
  418.  
  419.   //w0 = w1;                        // 1/zbuffer
  420.     v0 = v1;
  421.     u0 = u1;
  422.   }
  423.  
  424. //w = FLOAT_TO_FIX(w0);                    // 1/zbuffer
  425.   v = FLOAT_TO_FIX(v0);
  426.   u = FLOAT_TO_FIX(u0);
  427.   if((rlen = (len & SUBDIV_MASK) - 1)) {        // a) do not calc if only draw 1 pixel
  428.     end = sx + rlen;
  429.     w1 = 1 / (prew + end * tmap[7]);
  430.     v1 = (prev + end * tmap[4]) * w1;
  431.     u1 = (preu + end * tmap[1]) * w1;
  432.  
  433.   //dw = FLOAT_TO_FIX((w1 - w0) / rlen);        // 1/zbuffer
  434.     dv = FLOAT_TO_FIX((v1 - v0) / rlen);
  435.     du = FLOAT_TO_FIX((u1 - u0) / rlen);
  436.   }
  437.                             // a) but draw that pixel surely
  438.   draw_affine(rlen + 1, dest, u, v, du, dv);        // for the last pixel the du and dv are thrown away
  439. }
  440. /*
  441. // sx = 16, ex = 32
  442. sx    len    slen    rlen    e
  443. 16    15        15    31
  444. // sx = 16, ex = 33
  445. sx    len    slen    rlen    e
  446. 16    16    1        32
  447. // sx = 16, ex = 34
  448. sx    len    slen    rlen    e
  449. 16    17    1        32
  450. 32            1    33    ...
  451. //
  452. */
  453.